package com.my.java8;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.IntSupplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamTest {

	public static void main(String[] args) {
		List<Dish> menu = Arrays.asList(new Dish("pork", false, 800, Dish.Type.MEAT),
				new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT),
				new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("rice", true, 350, Dish.Type.OTHER),
				new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("pizza", true, 550, Dish.Type.OTHER),
				new Dish("prawns", false, 300, Dish.Type.FISH), new Dish("salmon", false, 450, Dish.Type.FISH));

		List<String> highCa = menu.stream().filter(d -> {
			System.out.println(d);
			return d.getCalories() > 300;
		}).map(Dish::getName).limit(3).collect(Collectors.toList());
		System.out.println(highCa);

		long count = menu.stream().filter(d -> d.getCalories() > 300).distinct().limit(3).count();

		List<String> words = Arrays.asList("Java8", "Lambdas", "In", "Action");
		List<Integer> wordLengths = words.stream().map(String::length).collect(Collectors.toList());

		List<Integer> numbers1 = Arrays.asList(1, 2, 3);
		List<Integer> numbers2 = Arrays.asList(3, 4);
		List<int[]> pairs = numbers1.stream()
				.flatMap(i -> numbers2.stream().filter(j -> (i + j) % 3 == 0).map(j -> new int[] { i, j }))
				.collect(Collectors.toList());
		pairs.forEach(pair -> System.out.println(Arrays.toString(pair)));

		System.out.println(numbers1.stream().anyMatch(a -> a % 3 == 0));
		System.out.println(numbers1.stream().allMatch(a -> a % 3 == 0));

		numbers1.stream().filter(a -> a % 4 == 0).findAny().ifPresent(b -> System.out.println(b));
		Optional<Integer> num3 = numbers1.stream().filter(a -> a % 3 == 0).findAny();

		int sum = numbers1.stream().reduce(0, (a, b) -> a + b);

		Optional<Integer> max = numbers1.stream().reduce(Integer::max);

		Trader raoul = new Trader("Raoul", "Cambridge");
		Trader mario = new Trader("Mario", "Milan");
		Trader alan = new Trader("Alan", "Cambridge");
		Trader brian = new Trader("Brian", "Cambridge");
		List<Transaction> transactions = Arrays.asList(new Transaction(brian, 2011, 300),
				new Transaction(raoul, 2012, 1000), new Transaction(raoul, 2011, 400),
				new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950));
		
		
		
		transactions.stream().filter(t->t.getYear()==2011)
			.sorted((t1,t2)->t1.getValue()>t2.getValue()?1:-1)
			.collect(Collectors.toList()).forEach(System.out::println);
		
		Set<String> cities =
				transactions.stream()
				.map(transaction -> transaction.getTrader().getCity())
				.collect(Collectors.toSet());
		
		String traderStr = transactions.stream().map(t->t.getTrader().getName())
				.distinct().sorted().reduce("",(n1,n2)->n1+","+n2);
		System.out.println(traderStr);
		
		int sum2 = transactions.stream().mapToInt(Transaction::getYear).sum();
		System.out.println(sum2);
		
		IntStream.range(1, 100).boxed();
		
		Stream<int[]> pythagoreanTriples =
				IntStream.rangeClosed(1, 100).boxed()
				.flatMap(a ->IntStream.rangeClosed(a, 100)
						.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
						.mapToObj(b ->
						new int[]{a, b, (int)Math.sqrt(a * a + b * b)})
						);
		pythagoreanTriples.limit(5).forEach(a->System.out.println(Arrays.toString(a)));
		
		Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
		stream.map(String::toUpperCase).forEach(System.out::println);
		
		Stream<String> emptyStream =Stream.empty();
		
		/*try(Stream<String> lines = Files.lines(Paths.get("c:/IcbcToolBar.txt"), Charset.defaultCharset())){
			System.out.println(lines.flatMap(line->Arrays.stream(line.split(""))).distinct().count());
		} catch (IOException e) {
			e.printStackTrace();
		}*/
		
		Stream.iterate(new int[]{0, 1},
				t -> new int[]{t[1],t[0] + t[1]})
				.limit(10)
				.map(t -> t[0])
				.forEach(System.out::println);
		
		IntStream.generate(new IntSupplier() {
			private int previous = 0;
			private int current = 1;
			@Override
			public int getAsInt() {
				int oldPrevious = this.previous;
				int nextValue = this.previous + this.current;
				this.previous = this.current;
				this.current = nextValue;
				return oldPrevious;
			}
		}).limit(10).forEach(System.out::println);
		
	}

	public static class Trader {
		private final String name;
		private final String city;

		public Trader(String n, String c) {
			this.name = n;
			this.city = c;
		}

		public String getName() {
			return this.name;
		}

		public String getCity() {
			return this.city;
		}

		public String toString() {
			return "Trader:" + this.name + " in " + this.city;
		}
	}

	public static class Transaction {
		private final Trader trader;
		private final int year;
		private final int value;

		public Transaction(Trader trader, int year, int value) {
			this.trader = trader;
			this.year = year;
			this.value = value;
		}

		public Trader getTrader() {
			return this.trader;
		}

		public int getYear() {
			return this.year;
		}

		public int getValue() {
			return this.value;
		}

		public String toString() {
			return "{" + this.trader + ", " + "year: " + this.year + ", " + "value:" + this.value + "}";
		}

	}

}
